home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / devSCSIRobot.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  19KB  |  741 lines

  1. /* 
  2.  * devSCSIRobot.c --
  3.  *
  4.  *      The standard Open, IOControl, and Close operations
  5.  *      are defined here for a SCSI Tape Robot.
  6.  *
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *
  15.  * Copyright 1992 Regents of the University of California
  16.  * All rights reserved.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devSCSIRobot.c,v 9.4 92/05/13 13:23:53 mottsmth Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23. #include <sprite.h>
  24. #include <stdio.h>
  25. #include <bstring.h>
  26. #include <string.h>
  27. #include <fs.h>
  28. #include <dev.h>
  29. #include <devInt.h>
  30. #include <sys/scsi.h>
  31. #include <scsiDevice.h>
  32. #include <devSCSIRobot.h>
  33. #include <dev/scsi.h>
  34. #include <stdlib.h>
  35. #include <dbg.h>
  36. #include <mach.h>
  37.      
  38. static ReturnStatus InitExbRobot _ARGS_((Fs_Device *devicePtr,
  39.      ScsiDevice *devPtr));
  40. static ReturnStatus InitError _ARGS_((ScsiDevice *devPtr, 
  41.      ScsiCmd *scsiCmdPtr));
  42.      
  43.  
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * InitError --
  48.  *
  49.  *    Initial error proc used by InitExbRobot when it is initializing
  50.  *    things for the real error handlers.  
  51.  *
  52.  * Results:
  53.  *    DEV_OFFLINE if the device is offline, SUCCESS otherwise.
  54.  *
  55.  * Side effects:
  56.  *    None.
  57.  *
  58.  *----------------------------------------------------------------------
  59.  */
  60. /*ARGSUSED*/
  61. static ReturnStatus
  62. InitError(devPtr, scsiCmdPtr)
  63.     ScsiDevice     *devPtr;    /* SCSI device that's complaining. */
  64.     ScsiCmd    *scsiCmdPtr;    /* SCSI command that had the problem. */
  65. {
  66.     ScsiStatus         *scsiStatusPtr;
  67.     unsigned char    statusByte;
  68.     ScsiClass7Sense    *sensePtr;
  69.  
  70.     statusByte = (unsigned char) scsiCmdPtr->statusByte;
  71.     scsiStatusPtr = (ScsiStatus *) &statusByte;
  72.     if (!scsiStatusPtr->check) {
  73.     if (scsiStatusPtr->busy) {
  74.         return DEV_OFFLINE;
  75.     }
  76.     return SUCCESS;
  77.     }
  78.     sensePtr = (ScsiClass7Sense *) scsiCmdPtr->senseBuffer;
  79.     if (sensePtr->key == SCSI_CLASS7_NOT_READY) {
  80.     return DEV_OFFLINE;
  81.     }
  82.     if (sensePtr->key == SCSI_CLASS7_NO_SENSE) {
  83.     return SUCCESS;
  84.     }
  85.     return FAILURE;
  86. }
  87.  
  88.  
  89.  
  90. /* 
  91.  *----------------------------------------------------------------------
  92.  *
  93.  * InitExbRobot --
  94.  *
  95.  *    Initialize the device driver state for a EXB-120 tape robot.
  96.  *
  97.  * Results:
  98.  *    SUCCESS, if the robot driver is successfully initialized. A
  99.  *    Sprite error code otherwise.
  100.  *
  101.  * Side effects:
  102.  *
  103.  *----------------------------------------------------------------------
  104.  */    
  105. /*ARGSUSED*/
  106. static ReturnStatus
  107. InitExbRobot(devicePtr, devPtr)
  108.      Fs_Device    *devicePtr;    /* Device info, unit number, etc. */
  109.      ScsiDevice    *devPtr;    /* Attached EXB-120. */
  110. {
  111.     ScsiExbRobot    robotData;
  112.     ScsiExbRobot     *robotPtr;
  113.     ReturnStatus     status;
  114.     ExbRobotInquiryData *inquiryDataPtr;
  115.  
  116.     /*
  117.      * Determine the type of device from the inquiry return
  118.      * by the attach.  Reject device if not a jukebox.
  119.      */
  120.  
  121.     inquiryDataPtr = (ExbRobotInquiryData *) (devPtr->inquiryDataPtr);
  122.     if (devPtr->inquiryLength > 0) {
  123.     if (inquiryDataPtr->type != SCSI_MEDIUM_CHANGER_TYPE ||
  124.         devPtr->inquiryLength != sizeof(ExbRobotInquiryData)) {
  125.         return DEV_NO_DEVICE;
  126.     }
  127.     }
  128.     devPtr->errorProc = InitError; 
  129.  
  130.     /*
  131.      * Do a quick test to see if the device is ready.
  132.      */ 
  133.  
  134.     status = DevScsiTestReady(devPtr);
  135.     if (status != SUCCESS) {
  136.     /*
  137.      * Give up if it still isn't ready.
  138.      */
  139.     status = DevScsiTestReady(devPtr);
  140.     if (status != SUCCESS) {
  141.         return status;
  142.     }
  143.     }
  144.     if (devicePtr->data == (ClientData) NIL) {
  145.     robotPtr = &robotData;
  146.     bzero((char *) robotPtr, sizeof(ScsiExbRobot));
  147.     robotPtr->devPtr = devPtr;
  148.     robotPtr->state = SCSI_ROBOT_CLOSED;
  149.     robotPtr->name = "SCSI Robot";
  150.     robotPtr->chmAddr = (unsigned) 0x79; /* Default. */
  151.     }
  152.     else {
  153.     robotPtr = (ScsiExbRobot *) (devicePtr->data);
  154.     }
  155.  
  156.     /*
  157.      * Allocate and return the ScsiExbRobot structure in the data field
  158.      * of the Fs_Device.
  159.      */
  160.     
  161.     if (status == SUCCESS  &&  devicePtr->data == (ClientData) NIL) {
  162.     robotPtr = (ScsiExbRobot *) malloc(sizeof(ScsiExbRobot));
  163.     *robotPtr = robotData;
  164.     devicePtr->data = (ClientData) robotPtr;
  165.     devPtr->clientData = (ClientData) robotPtr;
  166.     if (devPtr->errorProc == InitError) {
  167.         devPtr->errorProc = DevSCSIExbRobotError;
  168.     }
  169.     }
  170.     return status;
  171. }
  172.  
  173.  
  174.  
  175. /*
  176.  *----------------------------------------------------------------------
  177.  *
  178.  * DevSCSIExbRobotError --
  179.  *
  180.  *    Map SCSI errors indicated by the sense data into Sprite ReturnStatus
  181.  *    and error message. This proceedure handles two types of 
  182.  *    sense data Class 0 and class 7.
  183.  *
  184.  * Results:
  185.  *    A sprite error code.
  186.  *
  187.  * Side effects:
  188.  *    None.
  189.  *
  190.  *----------------------------------------------------------------------
  191.  */
  192. /* ARGSUSED */
  193. ReturnStatus
  194. DevSCSIExbRobotError(devPtr, scsiCmdPtr)
  195.      ScsiDevice     *devPtr;    /* SCSI Device that's complaining. */
  196.      ScsiCmd        *scsiCmdPtr;    /* SCSI command that had the problem. */
  197. {
  198.     char errorString[MAX_SCSI_ERROR_STRING];
  199.     char *name;
  200.     ScsiExbRobot *robotPtr;
  201.     int senseLength;
  202.     ScsiClass0Sense *sensePtr;
  203.     unsigned char statusByte;
  204.     ScsiStatus *statusPtr;
  205.     ReturnStatus status;
  206.     
  207.     statusByte = scsiCmdPtr->statusByte;
  208.     statusPtr = (ScsiStatus *) &statusByte;
  209.     sensePtr = (ScsiClass0Sense *) scsiCmdPtr->senseBuffer;
  210.     senseLength = scsiCmdPtr->senseLen;
  211.     robotPtr = (ScsiExbRobot *) devPtr->clientData;
  212.     name = devPtr->locationName;
  213.  
  214.     if (!statusPtr->check) {
  215.     if (SCSI_RESERVED_STATUS(statusByte)  ||  statusPtr->intStatus) {
  216.         printf("Warning: %s at %s unknown status byte 0x%x\n",
  217.            robotPtr->name, name, statusByte);
  218.         return SUCCESS;
  219.     }
  220.     if (statusPtr->busy) {
  221.         return DEV_OFFLINE;
  222.     }
  223.     return SUCCESS;
  224.     }
  225.     if (senseLength == 0) {
  226.     printf("Warning: %s at %s error: no sense data\n", robotPtr->name, name);
  227.     return DEV_NO_SENSE;
  228.     }
  229.  
  230.     /*
  231.      * The EXB-120 only returns class 7 (extended sense) data.
  232.      */
  233.     
  234.     DevScsiMapClass7Sense(senseLength, (char *)sensePtr,
  235.               &status, errorString);
  236.     if (errorString[0]) {
  237.     printf("Warning: %s at %s error: %s\n", robotPtr->name, name,
  238.            errorString);
  239.     }
  240.     return status;
  241. }
  242.     
  243.  
  244.  
  245. /*
  246.  *---------------------------------------------------------------------
  247.  *
  248.  * DevSCSIExbRobotOpen --
  249.  *
  250.  *    Open an EXB-120 jukebox robot as a file. This routine verifies
  251.  *     the device's existence and sets any special mode flags.
  252.  *
  253.  * Results:
  254.  *    SUCCESS if the device is online.
  255.  *
  256.  * Side effects:
  257.  *     None.
  258.  *
  259.  *---------------------------------------------------------------------
  260.  */
  261. /* ARGSUSED */
  262. ReturnStatus
  263. DevSCSIExbRobotOpen(devicePtr, useFlags, token, flagsPtr)
  264.      Fs_Device *devicePtr;    /* Device info, lun, etc. */
  265.      int useFlags;        /* Flags from the stream being opened (unused) */
  266.      Fs_NotifyToken token;    /* Call-back token for input (unused) */
  267.      int *flagsPtr;        /* OUT: Device flags (unused) */
  268. {
  269.     ReturnStatus status;
  270.     ScsiDevice *devPtr;
  271.     ScsiExbRobot *robotPtr;
  272.     
  273.     robotPtr = (ScsiExbRobot *) (devicePtr->data);
  274.     if (robotPtr == (ScsiExbRobot *) NIL) {
  275.     /*
  276.      * Ask the HBA to set up the path to the device with FIFO ordering
  277.      * of requests.
  278.      */
  279.     devPtr = DevScsiAttachDevice(devicePtr, DEV_QUEUE_FIFO_INSERT);
  280.     if (devPtr == (ScsiDevice *) NIL) {
  281.         return DEV_NO_DEVICE;
  282.     }
  283.     }
  284.     else {
  285.     /*
  286.      * If the robotPtr is already attached to the device, it must
  287.      * be busy.
  288.      */
  289.     return FS_FILE_BUSY;
  290.     }
  291.     status = InitExbRobot(devicePtr, devPtr);
  292.     return status;
  293. }
  294.  
  295.  
  296.  
  297. /*---------------------------------------------------------------------
  298.  *
  299.  * DevSCSIExbRobotClose --
  300.  *
  301.  *    Close an EXB-120 jukebox. Free all data structures associated
  302.  *     with the jukebox.
  303.  *
  304.  * Results:
  305.  *    None.
  306.  *
  307.  * Side effects:
  308.  *    None.
  309.  *
  310.  *----------------------------------------------------------------------
  311.  */
  312.  
  313. /*ARGSUSED*/
  314. ReturnStatus
  315. DevSCSIExbRobotClose(devicePtr, useFlags, openCount, writerCount)
  316.      Fs_Device     *devicePtr;
  317.      int useFlags;
  318.      int openCount;
  319.      int writerCount;
  320. {
  321.     ScsiExbRobot *robotPtr;
  322.     ReturnStatus status;
  323.  
  324.     status = SUCCESS;        /* There's no way we can fail. */
  325.  
  326.     robotPtr = (ScsiExbRobot *) (devicePtr->data);
  327.     if (openCount > 0) {
  328.     return status;
  329.     }
  330.  
  331.     (void) DevScsiReleaseDevice(robotPtr->devPtr);
  332.     free((char *) robotPtr);
  333.     devicePtr->data = (ClientData) NIL;
  334.     return status;
  335. }
  336.  
  337.  
  338.  
  339. /*
  340.  *------------------------------------------------------------------------
  341.  *
  342.  * DevSCSIExbRobotIOControl --
  343.  *
  344.  *     Do operations on the Exabyte EXB-120 Robot.
  345.  *
  346.  * Results:
  347.  *     The Sprite status.
  348.  *
  349.  * Side Effects:
  350.  *      None.
  351.  *
  352.  *-----------------------------------------------------------------------
  353.  */
  354. /*ARGSUSED*/
  355. ReturnStatus
  356. DevSCSIExbRobotIOControl(devicePtr, ioctlPtr, replyPtr)
  357.      Fs_Device         *devicePtr;
  358.      Fs_IOCParam    *ioctlPtr;    /* Standard I/O Control parameter block */
  359.      Fs_IOReply        *replyPtr;    /* Size of outBuffer and returned signal */
  360. {
  361.     ScsiExbRobot     *robotPtr;
  362.     ScsiCmd        scsiRobotCmd;
  363.     ReturnStatus     status;
  364.     Dev_RobotCommand     *cmdPtr;
  365.     int         scsiCmd;
  366.     int         amountTransferred;
  367.     ExbRobotModeSelectData    modeSelData;
  368.     
  369.     bzero((char *) &scsiRobotCmd, sizeof(ScsiCmd));
  370.  
  371.     robotPtr = (ScsiExbRobot *) (devicePtr->data);
  372.     if ((ioctlPtr->command & ~0xffff) == IOC_SCSI) {
  373.     status = DevScsiIOControl(robotPtr->devPtr, ioctlPtr, replyPtr);
  374.     return status;
  375.     }
  376.  
  377.     cmdPtr = (Dev_RobotCommand *) ioctlPtr->inBuffer;
  378.     amountTransferred = 0;
  379.  
  380.     switch (ioctlPtr->command) {
  381.     case IOC_ROBOT_INIT_ELEM_STATUS:
  382.     scsiCmd = SCSI_INIT_ELEM_STATUS;
  383.     ExbRobotInitElemStatus(&scsiRobotCmd, cmdPtr);
  384.     break;
  385.     case IOC_ROBOT_INQUIRY: 
  386.     scsiCmd = SCSI_INQUIRY;
  387.     if (ioctlPtr->outBuffer == NULL) {
  388.         return DEV_INVALID_ARG;
  389.     }
  390.     ExbRobotInquiry(&scsiRobotCmd,
  391.             (ExbRobotInquiryData *)ioctlPtr->outBuffer);
  392.     break;
  393.     case IOC_ROBOT_MODE_SEL: 
  394.     scsiCmd = SCSI_MODE_SELECT;
  395.     ExbModeSelect(&scsiRobotCmd, cmdPtr, NULL, 0);
  396.     break;
  397.     case IOC_ROBOT_DISPLAY: 
  398.     scsiCmd = SCSI_MODE_SELECT;
  399.     bzero((char *) &modeSelData, sizeof(ExbRobotModeSelectData));
  400.     ExbModeSelect(&scsiRobotCmd, cmdPtr,
  401.               (Address)&modeSelData, sizeof(modeSelData));
  402.     break;
  403.     case IOC_ROBOT_MOVE_MEDIUM:
  404.     scsiCmd = SCSI_MOVE_MEDIUM;
  405.     ExbMoveMedium(&scsiRobotCmd, robotPtr, cmdPtr);
  406.     break;
  407.     case IOC_ROBOT_POS_ELEM:
  408.     scsiCmd = SCSI_POSITION_ELEMENT;
  409.     ExbPosElem(&scsiRobotCmd, robotPtr, cmdPtr);
  410.     break;
  411.     case IOC_ROBOT_PREV_REMOVAL:
  412.     scsiCmd = SCSI_PREVENT_ALLOW;
  413.     ExbPrevRemoval(&scsiRobotCmd, cmdPtr);
  414.     break;
  415.     case IOC_ROBOT_NO_OP:
  416.     scsiCmd = SCSI_TEST_UNIT_READY;
  417.     scsiRobotCmd.commandBlockLen = 6;
  418.     break;
  419.     case IOC_ROBOT_REQ_SENSE:
  420.     scsiCmd = SCSI_REQUEST_SENSE;
  421.     if (ioctlPtr->outBuffer == NULL) {
  422.         return DEV_INVALID_ARG;
  423.     }
  424.     ExbReqSense(&scsiRobotCmd,
  425.             (ExbRobotSenseData *)ioctlPtr->outBuffer);
  426.     break;
  427.     default:
  428.     /* Invalid or Command not supported. */
  429.     scsiCmd = 0;
  430.     panic("Fs_IOControl -- Tape Robot: Unknown command %d\n", 
  431.           ioctlPtr->command);
  432.     }
  433.  
  434.     /* Since we've set up the SCSI CDB, send the block out. */
  435.  
  436.     status = DevScsiSendCmdSync(robotPtr->devPtr, &scsiRobotCmd, 
  437.                 &amountTransferred);
  438.     return status;
  439. }
  440.  
  441.  
  442.  
  443. /*
  444.  *---------------------------------------------------------------------
  445.  *
  446.  * ExbRobotInitElemStatus --
  447.  *
  448.  *    Fill in the SCSI CDB for an InitElemStatus command to an Exabyte
  449.  *      EXB-120 robot.
  450.  *     
  451.  * Results:
  452.  *    None.
  453.  *
  454.  * Side effects:
  455.  *     None.
  456.  *
  457.  *---------------------------------------------------------------------
  458.  */
  459. void
  460. ExbRobotInitElemStatus(scsiRobotCmdPtr, cmdPtr)
  461.      ScsiCmd        *scsiRobotCmdPtr;
  462.      Dev_RobotCommand     *cmdPtr;
  463. {
  464.     InitElemStatCommand *cdbPtr;
  465.     
  466.     cdbPtr = (InitElemStatCommand *) scsiRobotCmdPtr->commandBlock;
  467.     bzero((char *) cdbPtr, sizeof(InitElemStatCommand));
  468.     
  469.     scsiRobotCmdPtr->dataToDevice = FALSE;
  470.     scsiRobotCmdPtr->commandBlockLen = sizeof(InitElemStatCommand);
  471.  
  472.     /*
  473.      * Fill in Command Descriptor Block. All fields are initially assumed
  474.      * to contain 0.
  475.      */
  476.     
  477.     cdbPtr->command = SCSI_INIT_ELEM_STATUS;
  478.     cdbPtr->unitNumber = 0; 
  479.     cdbPtr->range = cmdPtr->range;
  480.     cdbPtr->elemAddr[0] = (cmdPtr->elemAddr) >> 8;
  481.     cdbPtr->elemAddr[1] = ((cmdPtr->elemAddr) << 24) >> 24;
  482.     cdbPtr->numElements[0] = (cmdPtr->numElements) >> 8;
  483.     cdbPtr->numElements[1] = ((cmdPtr->numElements) << 24) >> 24;
  484. }
  485.  
  486.  
  487.  
  488. /*
  489.  *---------------------------------------------------------------------
  490.  *
  491.  * ExbRobotInquiry --
  492.  *
  493.  *    Fill in the SCSI CDB for an Inquiry command to an Exabyte
  494.  *      EXB-120 robot.
  495.  *     
  496.  * Results:
  497.  *    None.
  498.  *
  499.  * Side effects:
  500.  *     
  501.  *
  502.  *---------------------------------------------------------------------
  503.  */
  504. void
  505. ExbRobotInquiry(scsiRobotCmdPtr, inquiryDataPtr)
  506.      ScsiCmd            *scsiRobotCmdPtr;
  507.      ExbRobotInquiryData    *inquiryDataPtr;
  508. {
  509.     ScsiInquiryCommand *cdbPtr;
  510.     
  511.     cdbPtr = (ScsiInquiryCommand *) scsiRobotCmdPtr->commandBlock;
  512.     bzero((char *) cdbPtr, sizeof(ScsiInquiryCommand));
  513.     
  514.     scsiRobotCmdPtr->dataToDevice = FALSE;
  515.     scsiRobotCmdPtr->bufferLen = sizeof(ExbRobotInquiryData);
  516.     scsiRobotCmdPtr->buffer = (Address) inquiryDataPtr;
  517.     scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiInquiryCommand);
  518.  
  519.     /*
  520.      * Fill in Command Descriptor Block. All fields are initially assumed
  521.      * to contain 0.
  522.      */
  523.     
  524.     cdbPtr->command = SCSI_INQUIRY;
  525.     cdbPtr->unitNumber = 0; 
  526.     cdbPtr->allocLength = sizeof(ExbRobotInquiryData);
  527. }
  528.  
  529.  
  530. /*----------------------------------------------------------------
  531.  *
  532.  * ExbModeSelect --
  533.  *
  534.  *    Fill in the SCSI CDB for a Mode Select Command to an
  535.  *    Exabyte EXB-120 robot.
  536.  *
  537.  * Results:
  538.  *    None.
  539.  *
  540.  * Side effects:
  541.  *     None.
  542.  *
  543.  *-----------------------------------------------------------------
  544.  */ 
  545. void
  546. ExbModeSelect(scsiRobotCmdPtr, cmdPtr, dataPtr, dataLength)
  547.      ScsiCmd        *scsiRobotCmdPtr;
  548.      Dev_RobotCommand    *cmdPtr;
  549.      Address        dataPtr;
  550.      unsigned int    dataLength;
  551. {
  552.     ScsiModeSelectCommand *cdbPtr;
  553.     
  554.     cdbPtr = (ScsiModeSelectCommand *) scsiRobotCmdPtr->commandBlock;
  555.  
  556.     if (dataPtr != NULL) {
  557.     scsiRobotCmdPtr->dataToDevice = TRUE;
  558.     ((ExbRobotModeSelectData *) dataPtr)->vendorUnique.mesgDispCntrl = 
  559.         cmdPtr->mesgDisplay;
  560.     strncpy(((ExbRobotModeSelectData *) dataPtr)->vendorUnique.displayMessage, 
  561.         cmdPtr->mesgString, 60);
  562.     ((ExbRobotModeSelectData *) dataPtr)->vendorUnique.paramListLength = 62;
  563.     }
  564.     else {
  565.     scsiRobotCmdPtr->dataToDevice = FALSE;
  566.     }
  567.     scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiModeSelectCommand);
  568.     scsiRobotCmdPtr->buffer = dataPtr;
  569.     scsiRobotCmdPtr->bufferLen = 68;
  570.  
  571.     /* Fill in Command Descriptor Block. */    
  572.     
  573.     cdbPtr->command = SCSI_MODE_SELECT;
  574.     cdbPtr->unitNumber = 0;
  575.     cdbPtr->pageFormat = 1;        
  576.     cdbPtr->savedPage = cmdPtr->savedPage;
  577.     cdbPtr->paramListLength = dataLength;
  578. }
  579.  
  580.  
  581.  
  582. /*
  583.  *---------------------------------------------------------------------
  584.  *
  585.  * ExbMoveMedium -- 
  586.  *
  587.  *    Fill in the SCSI CDB for a MoveMedium command to an Exabyte
  588.  *      EXB-120 robot.
  589.  *     
  590.  * Results:
  591.  *    None.
  592.  *
  593.  * Side effects:
  594.  *     None.
  595.  *
  596.  *---------------------------------------------------------------------
  597.  */
  598. void
  599. ExbMoveMedium(scsiRobotCmdPtr, robotPtr, cmdPtr)
  600.      ScsiCmd        *scsiRobotCmdPtr;
  601.      ScsiExbRobot    *robotPtr;
  602.      Dev_RobotCommand    *cmdPtr;
  603. {
  604.     MoveMediumCommand *cdbPtr;
  605.     
  606.     cdbPtr = (MoveMediumCommand *) scsiRobotCmdPtr->commandBlock;
  607.     bzero((char *) cdbPtr, sizeof(MoveMediumCommand));
  608.     
  609.     scsiRobotCmdPtr->dataToDevice = FALSE;
  610.     scsiRobotCmdPtr->bufferLen = 0;
  611.     scsiRobotCmdPtr->commandBlockLen = sizeof(MoveMediumCommand);
  612.  
  613.     /* Fill in CDB. */
  614.  
  615.     cdbPtr->command = SCSI_MOVE_MEDIUM;
  616.     cdbPtr->unitNumber = 0;
  617.     cdbPtr->transpElemAddr[1] = (robotPtr->chmAddr << 24) >> 24;
  618.     cdbPtr->transpElemAddr[0] = robotPtr->chmAddr >> 8;
  619.     cdbPtr->sourceAddr[1] = ((cmdPtr->sourceAddr) << 24) >> 24;
  620.     cdbPtr->sourceAddr[0] = (cmdPtr->sourceAddr) >> 8;
  621.     cdbPtr->destAddr[1] = ((cmdPtr->destAddr) << 24) >> 24;
  622.     cdbPtr->destAddr[0] = (cmdPtr->destAddr) >> 8;
  623.     cdbPtr->eePos = cmdPtr->eePos;
  624. }
  625.  
  626.  
  627.  
  628. /*--------------------------------------------------------------------
  629.  *
  630.  * ExbPosElem --
  631.  *
  632.  *    Fill in the SCSI CDB for a PositionToElement command to an 
  633.  *      Exabyte EXB-120 robot.
  634.  *     
  635.  * Results:
  636.  *    None.
  637.  *
  638.  * Side effects:
  639.  *     None.
  640.  *
  641.  *---------------------------------------------------------------------
  642.  */
  643. void
  644. ExbPosElem(scsiRobotCmdPtr, robotPtr, cmdPtr)
  645.      ScsiCmd        *scsiRobotCmdPtr;
  646.      ScsiExbRobot    *robotPtr;
  647.      Dev_RobotCommand    *cmdPtr;
  648. {
  649.     PositionRobotCommand *cdbPtr;
  650.  
  651.     cdbPtr = (PositionRobotCommand *) scsiRobotCmdPtr->commandBlock;
  652.     bzero((char *) cdbPtr, sizeof(PositionRobotCommand));
  653.  
  654.     scsiRobotCmdPtr->commandBlockLen = sizeof(PositionRobotCommand);
  655.     scsiRobotCmdPtr->bufferLen = 0;
  656.  
  657.     /* Fill in CDB. */
  658.  
  659.     cdbPtr->command = SCSI_POSITION_ELEMENT;    /* Position to Element Command. */
  660.     cdbPtr->unitNumber = 0;
  661.     cdbPtr->transpElemAddr[1] = (robotPtr->chmAddr << 24) >> 24;
  662.     cdbPtr->transpElemAddr[0] = robotPtr->chmAddr >> 8;
  663.     cdbPtr->destAddr[1] = ((cmdPtr->destAddr) << 24) >> 24;
  664.     cdbPtr->destAddr[0] = (cmdPtr->destAddr) >> 8;
  665. }
  666.  
  667.  
  668.  
  669. /*--------------------------------------------------------------------
  670.  *
  671.  * ExbPrevRemoval -- 
  672.  *
  673.  *    Fill in the SCSI CDB for a Prevent/Allow Medium Removal
  674.  *      command to an Exabyte EXB-120 robot.
  675.  *     
  676.  * Results:
  677.  *    None.
  678.  *
  679.  * Side effects:
  680.  *     None.
  681.  *
  682.  *---------------------------------------------------------------------
  683.  */
  684. void
  685. ExbPrevRemoval(scsiRobotCmdPtr, cmdPtr)
  686.      ScsiCmd         *scsiRobotCmdPtr;
  687.      Dev_RobotCommand     *cmdPtr;
  688. {
  689.     ScsiPreventAllowCmd *cdbPtr;
  690.  
  691.     cdbPtr = (ScsiPreventAllowCmd *) scsiRobotCmdPtr->commandBlock;
  692.     
  693.     scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiPreventAllowCmd);
  694.     scsiRobotCmdPtr->bufferLen = 0;
  695.  
  696.     /* Fill in CDB. */
  697.  
  698.     cdbPtr->command = SCSI_PREVENT_ALLOW;    /* 0x1e */
  699.     cdbPtr->unitNumber = 0;
  700.     cdbPtr->prevent = cmdPtr->prevAllow;
  701. }
  702.  
  703.  
  704.  
  705. /*--------------------------------------------------------------------
  706.  *
  707.  * ExbReqSense --
  708.  *
  709.  *    Fill in the SCSI CDB for a RequestSense command
  710.  *      to be sent to an Exabyte EXB-120 robot.
  711.  *     
  712.  * Results:
  713.  *    None.
  714.  *
  715.  * Side effects:
  716.  *     None.
  717.  *
  718.  *---------------------------------------------------------------------
  719.  */
  720. void
  721. ExbReqSense(scsiRobotCmdPtr, senseDataPtr)
  722.      ScsiCmd         *scsiRobotCmdPtr;
  723.      ExbRobotSenseData    *senseDataPtr;
  724. {
  725.     ScsiRequestSenseCmd *cdbPtr;
  726.  
  727.     cdbPtr = (ScsiRequestSenseCmd *) scsiRobotCmdPtr->commandBlock;
  728.     bzero((char *) cdbPtr, sizeof(ScsiRequestSenseCmd));
  729.  
  730.     scsiRobotCmdPtr->dataToDevice = FALSE;
  731.     scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiRequestSenseCmd);
  732.     scsiRobotCmdPtr->bufferLen = sizeof(ExbRobotSenseData);
  733.     scsiRobotCmdPtr->buffer = (Address) senseDataPtr;
  734.     
  735.     /* Fill in CDB. */
  736.  
  737.     cdbPtr->command = SCSI_REQUEST_SENSE;        /* 0x3 */
  738.     cdbPtr->unitNumber = 0;
  739.     cdbPtr->allocLen = SCSI_EXB_ROBOT_SENSE_LEN;
  740. }    
  741.